// PrintPreview.cs
// <copyright>Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <summary>This file contains code that creates a custom print preview
// dialog for a document.</summary>

using System;

namespace Scenario.Modeler
{

	/// <summary>This class implements a custom print preview
	/// dialog for a Visio document.</summary>
	public class PrintPreview
		: System.Windows.Forms.Form 
	{

		/// <summary>The document and printer information is needed for dialog
		/// and print processing.</summary>
		private Microsoft.Office.Interop.Visio.Document targetDocument;

		/// <summary>The document and printer information is needed for dialog
		/// and print processing.</summary>
		private string selectedPrinter;

		// Form controls are added automatically as the form is designed.
		private System.Windows.Forms.Button cancelButton;
		private System.Windows.Forms.Button printButton;
		private System.Windows.Forms.PictureBox drawingPicture;
		private System.Windows.Forms.Label noMetafileLabel;

		/// <summary>Required designer variable.</summary>
		private System.ComponentModel.Container components = null;

		/// <summary>This constructor only contains the form initialization
		/// that is added automatically.</summary>
		public PrintPreview() 
		{

			// Required for Windows Form Designer support
			InitializeComponent();
		}

		/// <summary>This implementation of the PreviewDrawing method can be
		/// used without providing a printer.  The default (active) printer will
		/// be used.</summary>
		/// <param name="subjectDocument">Visio document to view and print
		/// </param>
		public void PreviewDrawing(
			Microsoft.Office.Interop.Visio.Document subjectDocument) 
		{

			try 
			{

				// Call the main implementation of PreviewDrawing,
				// passing the active printer.
				PreviewDrawing(subjectDocument,
					subjectDocument.Application.ActivePrinter);
			}

			catch (Exception error) 
			{
				System.Diagnostics.Debug.WriteLine(error.Message);
			}
		}

		/// <summary>This implementation of the PreviewDrawing method takes
		/// both the Visio document and the printer.  The page's picture
		/// is loaded into the form control, and the information is saved
		/// for later printing.</summary>
		/// <remarks>The dialog must be shown with a call to ShowDialog()
		/// after this method is called.</remarks>
		/// <param name="subjectDocument">Visio document to view and print
		/// </param>
		/// <param name="printer">Desired printer to use</param>
		public void PreviewDrawing(
			Microsoft.Office.Interop.Visio.Document subjectDocument, 
			string printer) 
		{

			System.Drawing.Imaging.Metafile pageMetafile;
			Microsoft.Office.Interop.Visio.Shape temporaryShape = null;
			Microsoft.Office.Interop.Visio.Page firstPage = null;
			double pageWidth;
			double pageHeight;

			try 
			{

				targetDocument = subjectDocument;
				selectedPrinter = printer;
				firstPage = subjectDocument.Pages[1];

				// draw a  frame around the page so the bounding box of the
				// picture is the size of the page.
				pageWidth = firstPage.PageSheet.get_CellsSRC(
					(short)Microsoft.Office.Interop.Visio.VisSectionIndices.
					visSectionObject,
					(short)Microsoft.Office.Interop.Visio.VisRowIndices.
					visRowPage,
					(short)Microsoft.Office.Interop.Visio.VisCellIndices.
					visPageWidth).ResultIU;

				pageHeight = firstPage.PageSheet.get_CellsSRC(
					(short)Microsoft.Office.Interop.Visio.VisSectionIndices.
					visSectionObject,
					(short)Microsoft.Office.Interop.Visio.VisRowIndices.
					visRowPage,
					(short)Microsoft.Office.Interop.Visio.VisCellIndices.
					visPageHeight).ResultIU;

				temporaryShape = firstPage.DrawRectangle(0, 0, 
					pageWidth, pageHeight);

				temporaryShape.get_CellsSRC(
					(short)Microsoft.Office.Interop.Visio.VisSectionIndices.
					visSectionObject,
					(short)Microsoft.Office.Interop.Visio.VisRowIndices.
					visRowFill,
					(short)Microsoft.Office.Interop.Visio.VisCellIndices.
					visFillPattern).ResultIU = 0;

				// Get the metafile from the drawing
				pageMetafile = getMetafileFromPage(firstPage);

				// delete the temporary shape
				temporaryShape.Delete();

				if (pageMetafile != null) 
				{

					// Scale the metafile and insert it into the PictureBox
					showMetafile(drawingPicture, pageMetafile);
				}
				else 
				{

					// The picture isn't available.
					// Just show the not available message.
					noMetafileLabel.Visible = true;
					drawingPicture.Visible = false;
				}
			}

			catch (Exception error) 
			{
				System.Diagnostics.Debug.WriteLine(error.Message);
			}
		}

		/// <summary>Clean up any resources being used.  This is automatically
		/// added.</summary>
		/// <param name="disposing">true to release both managed and unmanaged
		/// resources; false to release only unmanaged resources.</param>
		protected override void Dispose(bool disposing) 
		{

			if (disposing) 
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}

			base.Dispose(disposing);
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent() 
		{

			this.cancelButton = new System.Windows.Forms.Button();
			this.printButton = new System.Windows.Forms.Button();
			this.drawingPicture = new System.Windows.Forms.PictureBox();
			this.noMetafileLabel = new System.Windows.Forms.Label();
			this.SuspendLayout();
			// 
			// cancelButton
			// 
			this.cancelButton.Location = new System.Drawing.Point(208, 240);
			this.cancelButton.Name = "cancelButton";
			this.cancelButton.TabIndex = 0;
			this.cancelButton.Text = "Cancel";
			this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
			// 
			// printButton
			// 
			this.printButton.Location = new System.Drawing.Point(120, 240);
			this.printButton.Name = "printButton";
			this.printButton.TabIndex = 1;
			this.printButton.Text = "Print";
			this.printButton.Click += new System.EventHandler(this.printButton_Click);
			// 
			// drawingPicture
			// 
			this.drawingPicture.BackColor = System.Drawing.SystemColors.Window;
			this.drawingPicture.Location = new System.Drawing.Point(8, 8);
			this.drawingPicture.Name = "drawingPicture";
			this.drawingPicture.Size = new System.Drawing.Size(272, 224);
			this.drawingPicture.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
			this.drawingPicture.TabIndex = 2;
			this.drawingPicture.TabStop = false;
			// 
			// noMetafileLabel
			// 
			this.noMetafileLabel.BackColor = System.Drawing.SystemColors.Control;
			this.noMetafileLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 18F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.noMetafileLabel.Location = new System.Drawing.Point(32, 80);
			this.noMetafileLabel.Name = "noMetafileLabel";
			this.noMetafileLabel.Size = new System.Drawing.Size(224, 72);
			this.noMetafileLabel.TabIndex = 3;
			this.noMetafileLabel.Text = "No Preview is Available";
			this.noMetafileLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
			this.noMetafileLabel.Visible = false;
			// 
			// PrintPreview
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(288, 272);
			this.Controls.Add(this.noMetafileLabel);
			this.Controls.Add(this.drawingPicture);
			this.Controls.Add(this.printButton);
			this.Controls.Add(this.cancelButton);
			this.FormBorderStyle = 
				System.Windows.Forms.FormBorderStyle.FixedSingle;
			this.MinimizeBox = false;
			this.MaximizeBox = false;
			this.Name = "PrintPreview";
			this.Text = "PrintPreview";
			this.ResumeLayout(false);
		}
		#endregion

		/// <summary>This handler is called when the user clicks on the
		/// Cancel button. The form is closed.</summary>
		/// <param name="sender">Object raising the event</param>
		/// <param name="e">Event arguments</param>
		private void cancelButton_Click(object sender,
			System.EventArgs e) 
		{
		
			// Close the dialog.
			Close();
		}

		/// <summary>This handler is called when the user clicks on the
		/// Print button.  The document is printed using the Visio Print
		/// method.</summary>
		/// <remarks>Classes in managed code can be used to perform this
		/// operation by overriding the PrintPage event and providing the
		/// Visio Picture for each page as it's printed.  The Visio
		/// Print method is available for both in-proc and out-of-proc
		/// processes.</remarks>
		/// <param name="sender">Object raising the event</param>
		/// <param name="e">Event arguments</param>
		private void printButton_Click(object sender,
			System.EventArgs e) 
		{
		
			string currentActivePrinter;

			try 
			{
		
				// Set up the desired printer.  Save the current printer
				// so that it can be restored when this print process is
				// done.
				currentActivePrinter =
					targetDocument.Application.ActivePrinter;
				if (currentActivePrinter != selectedPrinter) 
				{

					targetDocument.Application.ActivePrinter = selectedPrinter;
				}

				// Use the Visio print command to print the document.
				System.Windows.Forms.Cursor oldCursor;
				oldCursor = Cursor;
				Cursor = System.Windows.Forms.Cursors.WaitCursor;

				targetDocument.Print();
				Cursor = oldCursor;

				// Restore the original active printer.
				if (currentActivePrinter != selectedPrinter) 
				{

					targetDocument.Application.ActivePrinter =
						currentActivePrinter;
				}
			}

			catch (Exception error) 
			{
				System.Diagnostics.Debug.WriteLine(error.Message);
			}
		}

		/// <summary>Display the metafile in a picture box control</summary>
		/// <remarks>This scales the metafile to fit the picture box control
		/// and adjusts the picture box width and height to maintain the
		/// correct aspect ratio.</remarks>
		/// <param name="pictureBox">PictureBox to display metafile in</param>
		/// <param name="metafile">Metafile to display in the picture box</param>
		private void showMetafile(System.Windows.Forms.PictureBox pictureBox, 
			System.Drawing.Imaging.Metafile metafile) 
		{

			System.Drawing.Image metafileImage;
			System.Drawing.Rectangle pictureBoxRect;
			double scale;
			double scaleWidth;
			int pictureWidth;
			int pictureHeight;

			pictureBoxRect = pictureBox.ClientRectangle;

			if ((metafile.Height > 0) && (metafile.Width > 0)) 
			{

				scale = (double)pictureBoxRect.Height / 
					metafile.Height;
				scaleWidth = (double)pictureBoxRect.Width / 
					metafile.Width;

				if (scaleWidth < scale) 
				{
					scale = scaleWidth;
				}

				pictureWidth = (int)(metafile.Width * scale);
				pictureHeight = (int)(metafile.Height * scale);

				metafileImage = metafile.GetThumbnailImage(pictureWidth,
					pictureHeight, null, IntPtr.Zero);

				// Load the metafile into the control.
				pictureBox.Image = metafileImage;

				// center the picture control
				pictureBox.Left = 
					(ClientRectangle.Width - pictureWidth) / 2;
				pictureBox.Width = pictureWidth;
				pictureBox.Height = pictureHeight;
			}
		}
		/// <summary>Get a metafile representing the Visio page</summary>
		/// <remarks>This will first try the page.Picture method. If that fails
		/// (typically because Visio is out-of-process) this will export
		/// the page to a temporary file in enhanced metafile format.</remarks>
		/// <param name="subjectPage">Visio page to get metafile of</param>
		/// <returns>Metafile if available, otherwise null</returns>
		private System.Drawing.Imaging.Metafile getMetafileFromPage(
			Microsoft.Office.Interop.Visio.Page subjectPage) 
		{

			System.Drawing.Imaging.Metafile pageMetafile = null;
			stdole.IPictureDisp pagePicture;
			string temporaryFileName;

			try 
			{

				// Get the metafile from the drawing
				// Visio returns an IPictureDisp interface which cannot be
				// marshaled between processes. If Visio is out of process then
				// a COMException will be thrown.
				pagePicture = subjectPage.Picture;
				pageMetafile = new System.Drawing.Imaging.Metafile(
					(IntPtr)pagePicture.Handle, false);
			}
			catch (System.Runtime.InteropServices.COMException) 
			{
				// ignore this exception
			}

			if (pageMetafile == null) 
			{

				// save the page as an enhanced metafile
				temporaryFileName = System.IO.Path.GetTempFileName();
				System.IO.File.Delete(temporaryFileName);
				temporaryFileName = System.IO.Path.ChangeExtension(
					temporaryFileName, "emf");

				subjectPage.Export(temporaryFileName);
				pageMetafile = (System.Drawing.Imaging.Metafile) new 
					System.Drawing.Imaging.Metafile(temporaryFileName);
			}

			return pageMetafile;
		}
	}
}
